Skip to content

fix gps metadata being stripped from exports (#1165)#1207

Open
Waynting wants to merge 1 commit into
CyberTimon:mainfrom
Waynting:fix/1165-gps-export-preserved
Open

fix gps metadata being stripped from exports (#1165)#1207
Waynting wants to merge 1 commit into
CyberTimon:mainfrom
Waynting:fix/1165-gps-export-preserved

Conversation

@Waynting

Copy link
Copy Markdown

Summary

Fixes #1165. GPS EXIF (location data) was always being stripped on export, even with Remove location data turned off.

Root cause

write_image_with_metadata has three branches for sourcing the original image's metadata: the .rrdata sidecar, kamadak-exif (JPEG/PNG), and rawler (RAW). Only the kamadak and rawler branches had GPS-reading code.

Opening any image in the app triggers persist_exif_if_missing (image_loader.rs:81), which writes the .rrdata sidecar. From then on the sidecar branch fires on every export — silently bypassing both GPS code paths. So in practice strip_gps=false did nothing for any image you'd opened in the editor.

Affects JPEG (as reported) and RAW (same mechanism, just less likely to be noticed).

Fix

GPS reading is orthogonal to the rest of the metadata sourcing. Lifted GPS reading out of the per-branch logic into two helpers and added a single tail call that runs unconditionally when !strip_gps:

if !strip_gps {
    if is_raw_file(original_path_str) {
        apply_gps_from_rawler(&mut metadata, original_path_str);
    } else {
        apply_gps_from_kamadak(&mut metadata, original_path);
    }
}

The sidecar / kamadak / rawler branches now handle only the non-GPS metadata they always did. GPS is re-read from the source file rather than parsed back from the sidecar's display strings (lossy — "40 deg 26' 12.345\"" can't round-trip cleanly into the rationals little_exif needs).

Behavior table

Before After
JPEG + sidecar + strip_gps=false ❌ stripped ✅ preserved
JPEG + sidecar + strip_gps=true ✅ stripped ✅ stripped
RAW + sidecar + strip_gps=false ❌ stripped ✅ preserved
RAW + sidecar + strip_gps=true ✅ stripped ✅ stripped
TIFF output / keep_metadata=false (early return) (early return — unchanged)

Tests

Added two regression tests in exif_processing::tests. No new dependencies — tempfile, image, little_exif, kamadak-exif are all already in the project.

  • issue_1165_gps_preserved_when_sidecar_exists_and_strip_gps_false — reproduces the exact bug trigger (real GPS tags + .rrdata sidecar via persist_exif_if_missing), asserts GPS lat/lon/alt are preserved in the exported bytes.
  • issue_1165_gps_stripped_when_strip_gps_true — asserts the toggle still works.

Both pass:

test exif_processing::tests::issue_1165_gps_stripped_when_strip_gps_true ... ok
test exif_processing::tests::issue_1165_gps_preserved_when_sidecar_exists_and_strip_gps_false ... ok

Also verified:

  • cargo fmt --check clean on the file
  • cargo clippy --lib --tests --no-deps — no new warnings introduced

Notes

  • Bonus: the kamadak helper now also writes GPSAltitudeRef (above/below sea-level reference). The rawler branch already wrote it; added for symmetry. Harmless if downstream readers don't expect it.
  • Follow-up not done here: get_string_val closure is now defined in two places (the helper + the inline kamadak branch). Kept this PR narrow; happy to lift it to a module-level helper in a follow-up if you'd like.

Test plan

  • cargo test --lib exif_processing::tests
  • cargo fmt -- --check src/exif_processing.rs
  • cargo clippy --lib --tests --no-deps
  • Manual: open a GPS-tagged JPEG, export with "Remove location data" off → exiftool -GPS:all exported.jpg shows coords
  • Manual: same with the toggle on → no GPS tags in output

write_image_with_metadata has three branches for sourcing the original
image's metadata: the .rrdata sidecar, kamadak-exif, and rawler. Only the
kamadak and rawler branches had GPS-reading code. Opening any image
triggers persist_exif_if_missing, which writes a sidecar -- from then on
the sidecar branch fires on every export, silently bypassing both GPS
code paths. Affects JPEG (as reported) and any RAW the user has opened.

Lift GPS reading into two helpers (apply_gps_from_kamadak,
apply_gps_from_rawler) and run them at the tail of the function,
unconditionally when !strip_gps. The sidecar/kamadak/rawler branches now
handle only the non-GPS metadata they always did. Re-read GPS from the
source file rather than parsing the lossy display strings stored in the
sidecar.

Add two regression tests using only existing project deps (tempfile,
image, little_exif, kamadak-exif). The first reproduces the bug trigger
(real GPS + .rrdata sidecar) and asserts GPS is preserved; the second
asserts the strip toggle still works.

Bonus: kamadak helper now also writes GPSAltitudeRef -- the rawler
branch already did this, added for symmetry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Waynting
Waynting requested a review from CyberTimon as a code owner May 24, 2026 14:42
@Wakaba0815

Copy link
Copy Markdown

Can confirm this independently on v1.5.8 (Linux) with a real-world case — might be a useful additional data point since it shows the sidecar-path trigger very clearly.

Source: JPEG straight from a Samsung Galaxy S22 Ultra (firmware S908BXXSNGZD7), synced via Nextcloud instant upload. Full GPS EXIF block present and verified in the original:

[GPS] GPSVersionID : 2.2.0.0
[GPS] GPSLatitudeRef : North
[GPS] GPSLatitude : XX deg XX' XX.XX"
[GPS] GPSLongitudeRef : East
[GPS] GPSLongitude : XX deg XX' XX.XX"
[GPS] GPSAltitudeRef : Above Sea Level
[GPS] GPSAltitude : XXX m
[GPS] GPSDateStamp : 2026:07:01
[GPS] GPSTimeStamp : 11:40:10
[GPS] GPSProcessingMethod : GPS

(via exiftool -a -G1 -s file.jpg | grep -i gps — note: plain exiftool -gps:all without -a misleadingly shows only partial ref tags on this file due to duplicate IFD blocks, worth keeping in mind if others report inconsistent repro results.)

After opening the file in RapidRAW and exporting (tested with "Strip GPS" both ON and OFF — no difference in outcome), the exported JPEG has zero GPS tags, not even the refs:

exiftool -a -G1 -s export.jpg | grep -i gps
(no output)

This lines up exactly with the root cause described in #1207 — once the image is opened in the editor, persist_exif_if_missing writes a .rrdata sidecar, and from that point on write_image_with_metadata takes the sidecar path for export, which has no GPS read logic at all (unlike the kamadak-exif / rawler paths). So the "Strip GPS" toggle has no effect once a sidecar exists — it's not being ignored, it's just not reached.

Confirms this isn't camera- or format-specific — happy to test the fix in #1207 against this file if it'd help verification before merge.

@Waynting

Waynting commented Jul 7, 2026

Copy link
Copy Markdown
Author

Thanks @Wakaba0815 — this is a really useful data point, especially the note about needing exiftool -a on files with duplicate IFD blocks; that's exactly the kind of real-world case the synthetic test files in this PR can't reproduce.

Your read of the root cause matches the fix: GPS reading is now lifted out of the three metadata-source branches (sidecar / kamadak-exif / rawler) and runs unconditionally at the end of write_image_with_metadata whenever Strip GPS is off — so the sidecar path can no longer bypass it, and the toggle works regardless of whether an .rrdata sidecar exists.

Testing against your S22 Ultra file before merge would be very welcome. To build this branch:

gh pr checkout 1207    # or: git clone -b fix/1165-gps-export-preserved https://github.com/Waynting/RapidRAW
npm install
npm start              # runs the tauri dev build

Then repeat your exact repro: open the file in the editor (so the .rrdata sidecar exists), export once with Strip GPS off and once with it on, and verify with exiftool -a -G1 -s. Expected: full GPS block preserved (including refs and altitude) with the toggle off, zero GPS tags with it on.

If you want to run the regression tests too: cd src-tauri && cargo test exif_processing — the first one reproduces the sidecar trigger you described.

@Wakaba0815

Copy link
Copy Markdown

Tested PR #1207 against my S22 Ultra file (built from fix/1165-gps-export-preserved,
npm start dev build on Linux).

Repro steps: opened the file in the editor (so the .rrdata sidecar exists, matching
my original report), then exported once with Strip GPS off and once on.

Strip GPS off — full GPS block preserved:
[GPS] GPSLatitudeRef : North
[GPS] GPSLatitude : XX deg XX' XX.XX"
[GPS] GPSLongitudeRef : East
[GPS] GPSLongitude : XX deg XX' XX.XX"
[GPS] GPSAltitudeRef : Above Sea Level
[GPS] GPSAltitude : XXX m
[Composite] GPSAltitude : XXX m Above Sea Level
[Composite] GPSLatitude : XX deg XX' XX.XX" N
[Composite] GPSLongitude : XX deg XX' XX.XX" E
[Composite] GPSPosition : XX deg XX' XX.XX" N, XX deg XX' XX.XX" E
Strip GPS on — zero GPS tags, as expected.

Confirmed via exiftool -a -G1 -s <file> | grep -i gps on both exports. Fix works
correctly for my case — the sidecar-triggered bypass is resolved. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Location data stripped from exported JPEG

2 participants